using System;
using System.Collections.Generic;
using System.Linq;

namespace ICP_MS.Plugin.Experiment;

public class FindAbnormalData
{
	public static List<int> Find(List<double> dataList)
	{
		List<int> indexList = new List<int>();
		double sigma = GetSigma(dataList);
		double mean = dataList.Average();
		(double lowerWhisker, double upWhisker) boxPlot = GetBoxPlot(dataList.OrderBy((double p) => p).ToList());
		double lowerWhisker = boxPlot.lowerWhisker;
		double upWhisker = boxPlot.upWhisker;
		int seq = 0;
		foreach (double data in dataList)
		{
			int r = FindItem(data, sigma, mean);
			if (r != -1)
			{
				indexList.Add(seq);
			}
			else
			{
				r = FindItemBoxPlot(data, lowerWhisker, upWhisker);
				if (r != -1)
				{
					indexList.Add(seq);
				}
			}
			seq++;
		}
		return indexList;
	}

	public static double GetMeanData(List<double> original)
	{
		List<int> excludelist = Find(original);
		double mean = 0.0;
		double sum = 0.0;
		double count = 0.0;
		if (excludelist != null && excludelist.Count > 0)
		{
			int i;
			for (i = 0; i < original.Count; i++)
			{
				if (excludelist.FindIndex((int r) => r == i) == -1)
				{
					sum += original[i];
					count += 1.0;
				}
			}
			return sum / count;
		}
		return original.Average();
	}

	public static List<double> GetMeanDataList(List<List<double>> originaList)
	{
		List<double> results = new List<double>();
		foreach (List<double> origina in originaList)
		{
			double mean = GetMeanData(origina);
			results.Add(mean);
		}
		return results;
	}

	public static double GetSigma(List<double> dataList)
	{
		double u = dataList.Average();
		double sum = dataList.Sum((double p) => Math.Pow(p - u, 2.0));
		return Math.Sqrt(sum / (double)(dataList.Count - 1));
	}

	public static (double lowerWhisker, double upWhisker) GetBoxPlot(List<double> dataList)
	{
		if (!dataList.Any())
		{
			return (lowerWhisker: 0.0, upWhisker: 0.0);
		}
		int listCount = dataList.Count;
		double q2 = 0.0;
		double q1;
		if ((listCount + 1) % 4 == 0)
		{
			q1 = dataList[(listCount + 1) / 4];
			q2 = dataList[3 * (listCount + 1) / 4];
		}
		else
		{
			int index1 = (listCount + 1) / 4;
			int index2 = 3 * (listCount + 1) / 4;
			q1 = (dataList[index1 - 1] + dataList[index1]) / 2.0;
			q2 = (dataList[index2 - 1] + dataList[index2]) / 2.0;
		}
		double iqr = q2 - q1;
		double lowerWhisker = q1 - 1.5 * iqr;
		double upWhisker = q2 + 1.5 * iqr;
		return (lowerWhisker: lowerWhisker, upWhisker: upWhisker);
	}

	private static int FindItem(double data, double sigma, double mean)
	{
		if (data > mean + 3.0 * sigma || data < mean - 3.0 * sigma)
		{
			return 1;
		}
		return -1;
	}

	private static int FindItemBoxPlot(double data, double lowerWhisker, double upWhisker)
	{
		if (data > upWhisker || data < lowerWhisker)
		{
			return 1;
		}
		return -1;
	}
}
